package com.train.common.utils;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.train.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.stream.FileImageOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class ToolUtil   {

    private ToolUtil() {

    }


    public static String encryptName(String name) {
        if (StrUtil.isEmptyOrUndefined(name)
                || name.length() == 1) {
            return "*";
        }
        String startStr = name.substring(0, 1);
        String endStr = name.substring(name.length() - 1);
        if (name.length() == 2) {
            endStr = "";
        }
        return startStr + "*" + endStr;
    }

    /**
     * 拷贝
     *
     * @param cls
     * @param source
     * @param <T>
     * @return
     */
    public static <T> List<T> deepCopy(Class<T> cls, List<T> source) {
        List<T> copyList = new ArrayList<>();
        source.forEach(item -> {
            copyList.add(JSONUtil.toBean(JSONUtil.toJsonStr(item), cls));
        });
        return copyList;
    }


    public static long getTotalWeekendDayCountInRange(Date start, Date end, int[] days) {
        long total = 0;
        for (int day : days) {
            total += getWeekendDayCountInRange(start, end, day);
        }
        return total;
    }

    /**
     * 给定时间段和星期几，计算该时间段内共有多少个给定的星期几
     *
     * @param start 开始时间,格式yyyy-MM-dd
     * @param end   结束时间，格式yyyy-MM-dd
     * @param day   星期几，从星期一到星期天，分别用数字1-7表示
     * @return 星期几统计数
     */
    public static long getWeekendDayCountInRange(Date start, Date end, int day) {
        long sumDay = 0; // 计数
        try {
            Calendar startDate = Calendar.getInstance(); // 开始时间
            startDate.setTime(start);
            Calendar endDate = Calendar.getInstance(); // 结束时间
            endDate.setTime(end);

            int SW = startDate.get(Calendar.DAY_OF_WEEK) - 1; // 开始日期是星期几
            int EW = endDate.get(Calendar.DAY_OF_WEEK) - 1; // 结束日期是星期几

            long diff = endDate.getTimeInMillis() - startDate.getTimeInMillis();
            long days = diff / (1000 * 60 * 60 * 24); // 给定时间段内一共有多少天
            long w = Math.round(Math.ceil(((days + SW + (7 - EW)) / 7.0))); // 给定时间内，共有多少个星期
            sumDay = w; // 总的星期几统计数
            if (day < SW) // 给定的星期几小于起始日期的星期几，需要减少一天
                sumDay--;
            if (day > EW) // 给定的星期几大于结束日期的星期几，需要减少一天
                sumDay--;
        } catch (Exception se) {
            log.error("getWeekendDayCountInRange error", se);
        }
        return sumDay;
    }

    /**
     * 获取某段时间内的周一（二等等）的日期
     *
     * @param dataBegin 开始日期
     * @param dataEnd   结束日期
     * @param weekDays  获取周几，1－6代表周一到周六。0代表周日
     * @return 返回日期List
     */
    public static List<String> getDayOfWeekWithinDateInterval(String dataBegin, String dataEnd, int weekDays) {
        if (weekDays == 7) {
            weekDays = 0;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List<String> dateResult = new ArrayList<>();
        Calendar cal = Calendar.getInstance();
        String[] dateInterval = {dataBegin, dataEnd};
        Date[] dates = new Date[dateInterval.length];
        for (int i = 0; i < dateInterval.length; i++) {
            String[] ymd = dateInterval[i].split("[^\\d]+");
            cal.set(Integer.parseInt(ymd[0]), Integer.parseInt(ymd[1]) - 1, Integer.parseInt(ymd[2]));
            dates[i] = cal.getTime();
        }
        for (Date date = dates[0]; date.compareTo(dates[1]) <= 0; ) {
            cal.setTime(date);
            if (cal.get(Calendar.DAY_OF_WEEK) - 1 == weekDays) {
                String format = sdf.format(date);
                dateResult.add(format);
            }
            cal.add(Calendar.DATE, 1);
            date = cal.getTime();
        }
        return dateResult;
    }


    /**
     * 获取当前日期是星期几<br>
     *
     * @param date
     * @return 当前日期是星期几
     */
    public static String getWeekOfDate(String date, String pattern) {
        if (date == null) {
            return null;
        }
        SimpleDateFormat df = new SimpleDateFormat(pattern);
        try {
            return getWeekOfDate(df.parse(date));
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取当前日期是星期几<br>
     *
     * @param date
     * @return 当前日期是星期几
     */
    public static int getWeekNumOfDate(String date, String pattern) {
        SimpleDateFormat df = new SimpleDateFormat(pattern);
        try {
            return getWeekNumOfDate(df.parse(date));
        } catch (Exception ignored) {
        }
        return 0;
    }

    public static String getWeekOfDate(Date date) {
        String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0) w = 0;
        return weekDays[w];
    }

    public static int getWeekNumOfDate(Date date) {
        int[] weekDays = {0, 1, 2, 3, 4, 5, 6};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0) w = 0;
        int weekNum = weekDays[w];
        if (weekNum == 0) {
            weekNum = 7;
        }
        return weekNum;
    }

    public static final String nowStrYMD() {
        return dateToStrYMD(new Date());
    }

    public static final String dateToStrYMD(Date date) {
        SimpleDateFormat simpledateformat = new SimpleDateFormat("yyyyMMdd");
        return simpledateformat.format(date);
    }

    public static final String getDateToStrYMD(Date date) {
        SimpleDateFormat simpledateformat = new SimpleDateFormat("yyyy-MM-dd");
        return simpledateformat.format(date);
    }


    public static String filterFileName (String fileName){
        Pattern pattern = Pattern.compile("[\\s\\\\/:\\*\\?\\\"<>\\|]");
        Matcher matcher = pattern.matcher(fileName);
        fileName = matcher.replaceAll("");
        return fileName;
    }

    /**
     * LocalDate转Date
     *
     * @param localDate
     * @return
     */
    public static Date localDate2Date(LocalDate localDate) {
        if (null == localDate) {
            return null;
        }
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 字符串是否包含中文
     * @param str
     * @return
     */
    public static boolean isContainChinese(String str) {
        Pattern p = Pattern.compile("[\u4E00-\u9FA5|\\！|\\，|\\。|\\（|\\）|\\《|\\》|\\“|\\”|\\？|\\：|\\；|\\【|\\】]");
        Matcher m = p.matcher(str);
        return m.find();
    }

    //byte数组到图片到硬盘上
    public static void byte2Image(byte[] data,String dir,String fileName){
        if(data.length<3||dir.equals("")) return;//判断输入的byte是否为空
        try{
            File destFileDir = new File(dir);
            if(!destFileDir.exists()){
                destFileDir.mkdirs();
            }
            String path = dir + fileName;
            FileImageOutputStream imageOutput = new FileImageOutputStream(new File(path));//打开输入流
            imageOutput.write(data, 0, data.length);//将byte写入硬盘
            imageOutput.close();
            log.info("Make Picture success,Please find image in " + path);
        } catch(Exception ex) {
            log.error("Exception: " + ex);
            ex.printStackTrace();
        }
    }

    /**
     * 将二进制转换成文件保存
     * @param instreams 二进制流
     * @param imgPath 图片的保存路径
     * @param imgName 图片的名称
     * @return
     *      1：保存正常
     *      0：保存失败
     */
    public static int saveToImgByInputStream(InputStream instreams, String imgPath, String imgName){
        int stateInt = 1;
        if(instreams != null){
            try {
                File destFileDir = new File(imgPath);
                if(!destFileDir.exists()){
                    destFileDir.mkdirs();
                }

                File file=new File(imgPath,imgName);//可以是任何图片格式.jpg,.png等
                FileOutputStream fos=new FileOutputStream(file);
                byte[] b = new byte[1024];
                int nRead = 0;
                while ((nRead = instreams.read(b)) != -1) {
                    fos.write(b, 0, nRead);
                }
                fos.flush();
                fos.close();
            } catch (Exception e) {
                stateInt = 0;
                e.printStackTrace();
            } finally {
            }
        }
        return stateInt;
    }


    /**
     * 生成订单号(长度20)
     * @return
     */
    public static String getOrderNo() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmssSSS");
        String newDate = sdf.format(new Date());
        Random random = new Random();
        String result = "" + random.nextInt(10);
        return newDate + result;
    }


    /**
     * 元转换成分
     * @param amount
     * @return
     */
    public static String getMoney(String amount) {
        if(amount==null){
            return "";
        }
        // 金额转化为分为单位
        // 处理包含, ￥ 或者$的金额
        String currency =  amount.replaceAll("\\$|\\￥|\\,", "");
        int index = currency.indexOf(".");
        int length = currency.length();
        Long amLong = 0l;
        if(index == -1){
            amLong = Long.valueOf(currency+"00");
        }else if(length - index >= 3){
            amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));
        }else if(length - index == 2){
            amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);
        }else{
            amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");
        }
        return amLong.toString();
    }


    /**
     * 入参日期与系统日期对比，返回结果
     * 返回1表示当前日期 < 入参日期
     * 返回0表示日期相等 =
     * 返回-1表示当前日期 > 入参日期
     * @param paramDate
     * @return
     */
    public static long compNowTime(Date paramDate){
        Date date = cn.hutool.core.date.DateUtil.parse(ToolUtil.getDateToStrYMD(paramDate), "yyyy-MM-dd");
        Date now = cn.hutool.core.date.DateUtil.parse(ToolUtil.getDateToStrYMD(new Date()), "yyyy-MM-dd");
       // log.info("date:{},now:{}",date,now);
        long betweenDay = cn.hutool.core.date.DateUtil.compare(date,now); //日期对比（1:表示系统日期>上架日期，0：表示同一天）
        //log.info("betweenDay:{}",betweenDay);
        return betweenDay;
    }


    public static JSONObject post(String url, Object o) throws BusinessException {
        HttpRequest request = HttpUtil.createPost(url);
        request.contentType(ContentType.JSON.toString());
        request.body(JSONUtil.toJsonStr(o));
        HttpResponse response = request.execute();
        if (response.isOk()) {
            return JSONUtil.parseObj(response.body());
        } else {
            throw new BusinessException( "访问[" + url + "]失败， 错误返回: " + response.body());
        }
    }

    /**
     * 密码强度校验：6-20位，只能包含英文字母、数字或英文符号
     * @param password 待校验字符串
     * @return 合法返回true，否则false
     */
    public static boolean isValidPassword(String password) {
        if (password == null) return false;
        // 长度6-20
        if (password.length() < 6 || password.length() > 20) return false;
        // 正则：英文字母大小写 + 数字 + 英文符号（可打印ASCII除空格）
        return password.matches("^[A-Za-z0-9!\"#$%&'()*+,-./:;<=>?@\\[\\]^_`{|}~]+$");
    }

    /**
     * 账号格式校验：6-20位，只能包含英文字母（大小写）或数字
     * @param account 待校验字符串
     * @return 合法返回true，否则false
     */
    public static boolean isValidAccount(String account) {
        if (account == null) return false;
        // 长度6-20
        if (account.length() < 6 || account.length() > 20) return false;
        // 正则：英文字母大小写 + 数字
        return account.matches("^[A-Za-z0-9]+$");
    }

    /**
     * 姓名格式校验：1-20位，只能包含中文、英文字母（大小写）或数字
     * @param name 待校验字符串
     * @return 合法返回true，否则false
     */
    public static boolean isValidName(String name) {
        if (name == null) return false;
        // 长度1-20
        if (name.length() < 1 || name.length() > 20) return false;
        // 正则：中文[\u4E00-\u9FA5] + 英文字母大小写 + 数字
        return name.matches("^[\\u4E00-\\u9FA5A-Za-z0-9]+$");
    }
}
